/************************************************************************************\
This source file is part of the Universal Actor Library                              *
For latest info, see http://libuniactor.sourceforge.net/                             *
**************************************************************************************
Copyright (c) 2010 Kresimir Spes (kreso@cateia.com)                                  *
*                                                                                    *
* This program is free software; you can redistribute it and/or modify it under      *
* the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php   *
\************************************************************************************/
#include "Jobs.h"

namespace UniActor
{
	Job::Job()
	{
		mStarted=0;
		mActor=0;
	}

	Job::~Job()
	{
		
	}
	
	void Job::setOwner(Actor* actor)
	{
		mActor=actor;
	}

	float Job::calcOvertime()
	{
		return 0;
	}
	
	void Job::cancel()
	{
		
	}

	namespace Jobs
	{
		Move::Move() : Job(), mStartPos(-1,-1,-1)
		{
		}
		
		Move::Move(float dx,float dy,float dz) : Job(), mStartPos(-1,-1,-1)
		{
			gtypes::Vector3 v(dx,dy,dz);
			mDistanceTraveled=0;
			mWaypoints.push_back(v);
		}
		
		Move::Move(Move& m) : Job(), mStartPos(-1,-1,-1)
		{
			mActor=m.mActor;
			mStarted=m.mStarted;
			mWaypoints=m.mWaypoints;
			mStartPos=m.mStartPos;
			mDistanceTraveled=m.mDistanceTraveled;
			mDistanceToTravel=m.mDistanceToTravel;
		}

		Job* Move::clone()
		{
			return new Move(*this);
		}
		
		Move::~Move()
		{
			if (mActor) mActor->OnEndMovement();
		}
		
		void Move::updateToNextWaypoint()
		{
			mDistanceTraveled=0;
			mStartPos=mActor->getActorPosition();
			gtypes::Vector3 direction=(mWaypoints.front()-mStartPos);
			mDistanceToTravel=direction.length();
			mActor->setDirection(direction.normalized());
		}
		
		void Move::start()
		{
			updateToNextWaypoint();
			if (mDistanceToTravel > 0)
			{
				mActor->OnStartMovement();
				mStarted=1;
			}
			else mWaypoints.clear();
			
		}
		
		void Move::update(float time_increase)
		{
			mDistanceTraveled+=time_increase*mActor->getSpeed();
			if (mDistanceTraveled >= mDistanceToTravel)
			{
				mStartPos=mWaypoints.front();
				mActor->setPosition(mStartPos);
				mWaypoints.pop_front();
				if (mWaypoints.size() > 0) updateToNextWaypoint();
			}
			else
			{
				mActor->setPosition(mStartPos+mActor->getDirection()*mDistanceTraveled);
			}
		}
		
		bool Move::isDone()
		{
			return mWaypoints.size() == 0;
		}
		
		
		
		
		
		
		
		Animate::Animate() : Job()
		{
			mAnimationName="null";
			mAnimationTime=1;
			mTimer=0;
			mLoop=0;
		}
		
		Animate::Animate(chstr ani_name,bool loop) : Job()
		{
			mAnimationName=ani_name;
			mAnimationTime=-1;
			mTimer=0;
			mLoop=loop;
		}
		
		Animate::Animate(Animate& m) : Job()
		{
			mAnimationName=m.mAnimationName;
			mAnimationTime=m.mAnimationTime;
			mTimer=0;
			mLoop=m.mLoop;
		}

		Job* Animate::clone()
		{
			return new Animate(*this);
		}
		
		Animate::~Animate()
		{
			if (mActor) mActor->OnEndAnimation(mAnimationName);
		}
		
		void Animate::start()
		{
			mActor->OnStartAnimation(mAnimationName);
			mTimer=0;
			mStarted=1;
			if (mAnimationTime < 0) mAnimationTime=mActor->getAnimationTime(mAnimationName);
		}
		
		void Animate::update(float time_increase)
		{
			mTimer+=time_increase;
			if (mTimer > mAnimationTime)
			{
				if (mLoop) mTimer-=mAnimationTime;
				else       mTimer=mAnimationTime;
			}
			mActor->setAnimationFrame(mAnimationName,mTimer/mAnimationTime);
		}
		
		bool Animate::isDone()
		{
			if (mLoop) return 0;
			if (mAnimationTime < 0) return 0;
			return mTimer >= mAnimationTime;
		}
	}
}
